<?php

namespace Lib;

require_once 'Autoload.php';
require_once DIR_CONFIG . '/boot.php';

use Lib\Exception\NotFoundException,
    Lib\Util\Inflector,
    Lib\Util\Session,
    Lib\Request,
    Lib\Util\Util;

class Dispatcher {

    public static $routes = array();
    public static $catchNotFound = true;

    public static function dispatch() {
        $request = @$_GET['req'];

        self::loadRoutes();
    
        $req = self::parseRequest($request);
        $className = "Controller\\{$req->controller}";
        $ctrl = new $className($req);

        if (! method_exists($ctrl, $req->action)) {
            throw new NotFoundException("Action {$req->controller}/{$req->action}");
        }

        call_user_func_array(array($ctrl, $req->action), $req->params);

        if ($ctrl->autoRender) {
            $ctrl->display();
        }
    }

    public static function parseRequest($request) {
        $req = new Request;
        $req->_request = $request;

        // try with routes
        foreach (self::$routes as $regexp=>$data) {
            $regexp = preg_replace('/([\/\*])/', '\\\\\1', $regexp);
            if (preg_match('/^'.$regexp.'$/', "/".$request)) {
                $request = $data;
                break;
            }
        }

        // extract request items
        $requesItems = explode("/", preg_replace('/^\/+/', '', $request));

        // set controller
        $ctrl = array_shift($requesItems);
        try {
            $req->controller = self::getController($ctrl, $request);

            // set action
            $req->action = array_shift($requesItems);
            $req->action = empty($req->action) ? 'index' : $req->action;

            // set params
            $req->params = $requesItems;
        } catch (NotFoundException $e) {
            if (isset(self::$routes->{'*'}) && self::$catchNotFound) {
                self::$catchNotFound = false;
                $r = self::$routes->{'*'}. '/'.preg_replace('/^\//', '', $request);
                $req = self::parseRequest($r);
                $className = "Controller\\{$req->controller}";
                $ctrl = new $className($req);
            } else {
                throw $e;
            }
        }

        return $req;
    }

    protected static function loadRoutes() {
        $path   = DIR_CONFIG . DS . "routes.json";
        $json   = file_get_contents($path);
        self::$routes = json_decode($json);
    }

    protected static function getController($controllerName, $request) {
        // try with controller
        $className = Inflector::camelize($controllerName);
        if (class_exists("Controller\\" . $className)) {
            return $className;
        }

        // is it root?
        if (empty($controllerName))
            return 'App';

        throw new NotFoundException("Controller {$className}");
    }

}